#include<iostream>
#include<string>
#include<cerrno>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<stdint.h>
typedef signed short int unit16_t;
void Usage(std::string proc)
{
  std::cout<<"Usage: \n\t"<<proc<<" server_port"<<std::endl;
}
//./udp_server port
int main(int argc,char* argv[])
{
  if(argc!=2)
  {
    Usage(argv[0]);
    return -1;
  }
  const unit16_t port=atoi(argv[1]);
  //1.创建套接字，打开网络文件  
    int sock=socket(AF_INET,SOCK_DGRAM,0);//以文件形式将网卡设备打开
    if(sock<0)
    {
      std::cerr<<"socket creat error:"<<errno<<std::endl;
      return 1;
    }
  //2.给该服务器绑定端口和ip(特殊处理)
  struct sockaddr_in local;
  local.sin_family=AF_INET;
  local.sin_port=htons(port);//此处端口号，是我们计算机上的变量，是主机序列
  //a.需要将人识别的点分十进制，字符串风格的IP地址,转化为四字节整数IP
  //b.也需要考虑大小端
  //in_addr_t inet_addr(const char *cp);就能完成上面ab两个工作
  //坑:云服务器，不允许用户直接bind公网IP,另外，实际正常编写时，也不会指明IP
  //local.sin_addr.s_addr=inet_addr("150.158.100.44");//点分十进制，字符串风格[0-255],[0-255][0-255][0-255]
  //INADDR_ANY:如果你Bind的是确定的IP（主机），意味着只有发到该IP主机上面的数据才会交给你的网络进程，
  //但是一般服务器可能有多张网卡，配置多个IP，我们需要的不是某个IP上的数据，我们需要的时，所有发到该主机，发送到该端口的数据
  local.sin_addr.s_addr=INADDR_ANY;
  if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0)
  {
    std::cerr<<"bind error:"<<errno<<std::endl;
    return 2;
  }
  //3.提供服务
  bool quit=false;
  #define NUM 1024
  char buffer[NUM];
  while(!quit)
  {
    struct sockaddr_in peer;
    socklen_t len=sizeof(peer);
    //注意：我们默认认为通信的数据是双方在互发字符串
    ssize_t cnt=recvfrom(sock,buffer,sizeof(buffer)-1,0,(struct sockaddr*)&peer,&len);//读取客户端发来的消息
    if(cnt>0)
    {
      buffer[cnt]=0;//可以当成一个字符串命令
      FILE* fp=popen(buffer,"r");
      std::string echo_hello;
      char line[1024]={0};
      while(fgets(line,sizeof(line),fp)!=NULL)//fgets一次读一行
      {
        echo_hello+=line;
      }
      if(feof(fp))//判断是否将文件读到结尾
      {
        //读取结果完成
      }
      pclose(fp);
      std::cout<<"client#"<<buffer<<std::endl;
      //根据用户输入，构建一个新的返回字符串
      sendto(sock,echo_hello.c_str(),echo_hello.size(),0,(struct sockaddr*)&peer,len);
    }
    else{
      //TODO
    }
  }
  return 0;
}

